import time
import json
from pathlib import Path
import ctypes
import ctypes.wintypes
import threading

# 加载系统库
user32 = ctypes.WinDLL('user32', use_last_error=True)
gdi32 = ctypes.WinDLL('gdi32', use_last_error=True)

# 定义常量
HWND_DESKTOP = 0
SRCCOPY = 0x00CC0020
TRANSPARENT = 0x0001  # 透明背景模式
OPAQUE = 0x0002  # 不透明背景模式
RGB_RED = 0x000000FF  # 红色(0x00BBGGRR格式)
RGB_YELLOW = 0x0000FFFF  # 黄色
RGB_GREEN = 0x0000FF00  # 绿色
RGB_BLUE = 0x00FF0000  # 蓝色

# 函数原型原型定义
user32.GetDC.argtypes = [ctypes.wintypes.HWND]
user32.GetDC.restype = ctypes.wintypes.HDC

user32.ReleaseDC.argtypes = [ctypes.wintypes.HWND, ctypes.wintypes.HDC]
user32.ReleaseDC.restype = ctypes.c_int

user32.GetSystemMetrics.argtypes = [ctypes.c_int]
user32.GetSystemMetrics.restype = ctypes.c_int

user32.UpdateWindow.argtypes = [ctypes.wintypes.HWND]
user32.UpdateWindow.restype = ctypes.c_bool

gdi32.CreateCompatibleDC.argtypes = [ctypes.wintypes.HDC]
gdi32.CreateCompatibleDC.restype = ctypes.wintypes.HDC

gdi32.CreateCompatibleBitmap.argtypes = [ctypes.wintypes.HDC, ctypes.c_int, ctypes.c_int]
gdi32.CreateCompatibleBitmap.restype = ctypes.wintypes.HBITMAP

gdi32.SelectObject.argtypes = [ctypes.wintypes.HDC, ctypes.wintypes.HGDIOBJ]
gdi32.SelectObject.restype = ctypes.wintypes.HGDIOBJ

gdi32.DeleteObject.argtypes = [ctypes.wintypes.HGDIOBJ]
gdi32.DeleteObject.restype = ctypes.c_bool

gdi32.DeleteDC.argtypes = [ctypes.wintypes.HDC]
gdi32.DeleteDC.restype = ctypes.c_bool

gdi32.BitBlt.argtypes = [ctypes.wintypes.HDC, ctypes.c_int, ctypes.c_int, ctypes.c_int, ctypes.c_int,
                         ctypes.wintypes.HDC, ctypes.c_int, ctypes.c_int, ctypes.c_uint]
gdi32.BitBlt.restype = ctypes.c_bool

gdi32.CreateFontW.argtypes = [ctypes.c_int, ctypes.c_int, ctypes.c_int, ctypes.c_int, ctypes.c_int,
                              ctypes.c_uint, ctypes.c_uint, ctypes.c_uint, ctypes.c_uint, ctypes.c_uint,
                              ctypes.c_uint, ctypes.c_uint, ctypes.c_uint, ctypes.c_wchar_p]
gdi32.CreateFontW.restype = ctypes.wintypes.HFONT

gdi32.TextOutW.argtypes = [ctypes.wintypes.HDC, ctypes.c_int, ctypes.c_int, ctypes.c_wchar_p, ctypes.c_int]
gdi32.TextOutW.restype = ctypes.c_bool

gdi32.SetTextColor.argtypes = [ctypes.wintypes.HDC, ctypes.wintypes.COLORREF]
gdi32.SetTextColor.restype = ctypes.wintypes.COLORREF

gdi32.SetBkMode.argtypes = [ctypes.wintypes.HDC, ctypes.c_int]
gdi32.SetBkMode.restype = ctypes.c_int

gdi32.GetTextExtentPoint32W.argtypes = [ctypes.wintypes.HDC, ctypes.c_wchar_p, ctypes.c_int,
                                        ctypes.POINTER(ctypes.wintypes.SIZE)]
gdi32.GetTextExtentPoint32W.restype = ctypes.c_bool


def load_time_texts(json_path="time_texts.json"):
    """读取JSON配置文件"""
    if not Path(json_path).exists():
        default_data = {
            "0分:10秒": "别发呆",
            "0分:30秒": "下2矿",
            "1分:00秒": "下3矿",
            "1分:30秒": "起飞"
        }
        with open(json_path, "w", encoding="utf-8") as f:
            json.dump(default_data, f, ensure_ascii=False, indent=2)
        return default_data

    with open(json_path, "r", encoding="utf-8") as f:
        return json.load(f)


def draw_transparent_text(text, size=100, x=100, y=100, color=RGB_RED, font_name="SimHei"):
    """在内存DC中使用透明背景绘制文字并显示到桌面"""
    try:
        # 获取桌面设备上下文
        hdc_screen = user32.GetDC(HWND_DESKTOP)
        if not hdc_screen:
            raise ctypes.WinError(ctypes.get_last_error())

        # 创建内存设备上下文(内存DC)
        hdc_mem = gdi32.CreateCompatibleDC(hdc_screen)
        if not hdc_mem:
            raise ctypes.WinError(ctypes.get_last_error())

        # 创建字体
        hfont = gdi32.CreateFontW(
            size, 0, 0, 0, 400,  # 高度、宽度、角度、方向、粗细
            0, 0, 0, 1, 4,  # 斜体、下划线、删除线、字符集、输出精度
            0, 0, 0, font_name  # 剪辑精度、质量、间距、字体
        )
        if not hfont:
            raise ctypes.WinError(ctypes.get_last_error())

        try:
            # 选入字体
            hfont_old = gdi32.SelectObject(hdc_mem, hfont)
            if not hfont_old:
                raise ctypes.WinError(ctypes.get_last_error())

            # 获取文本尺寸
            text_size = ctypes.wintypes.SIZE()
            if not gdi32.GetTextExtentPoint32W(hdc_mem, text, len(text), ctypes.byref(text_size)):
                raise ctypes.WinError(ctypes.get_last_error())

            # 创建兼容位图
            w, h = text_size.cx + 20, text_size.cy + 20  # 增加一些边距
            hbm_mem = gdi32.CreateCompatibleBitmap(hdc_screen, w, h)
            if not hbm_mem:
                raise ctypes.WinError(ctypes.get_last_error())

            # 将位图选入内存DC
            hbm_old = gdi32.SelectObject(hdc_mem, hbm_mem)
            if not hbm_old:
                raise ctypes.WinError(ctypes.get_last_error())

            try:
                # 关键步骤：将内存DC中的文字背景设置为透明
                prev_mode = gdi32.SetBkMode(hdc_mem, TRANSPARENT)
                if prev_mode == 0:
                    raise ctypes.WinError(ctypes.get_last_error())

                # 设置文字颜色
                gdi32.SetTextColor(hdc_mem, color)

                # 在内存DC上绘制文字（背景已设置为透明）
                if not gdi32.TextOutW(hdc_mem, 10, 10, text, len(text)):
                    raise ctypes.WinError(ctypes.get_last_error())

                # 将内存DC内容复制到屏幕
                if not gdi32.BitBlt(hdc_screen, x, y, w, h, hdc_mem, 0, 0, SRCCOPY):
                    raise ctypes.WinError(ctypes.get_last_error())

                print(f"已绘制透明背景的文字: {text}")
                return (x, y, w, h)  # 返回绘制区域的坐标和尺寸

            finally:
                # 恢复原背景模式
                gdi32.SetBkMode(hdc_mem, prev_mode)
                # 清理资源
                gdi32.SelectObject(hdc_mem, hbm_old)
                gdi32.DeleteObject(hbm_mem)

        finally:
            # 恢复原字体
            gdi32.SelectObject(hdc_mem, hfont_old)
            gdi32.DeleteObject(hfont)

        # 释放桌面DC
        user32.ReleaseDC(HWND_DESKTOP, hdc_screen)

    except Exception as e:
        print(f"绘制错误: {str(e)}")
    return None


def clear_desktop_area(x, y, w, h):
    """清除桌面上指定区域的内容"""
    try:
        # 获取桌面设备上下文
        hdc_screen = user32.GetDC(HWND_DESKTOP)
        if not hdc_screen:
            raise ctypes.WinError(ctypes.get_last_error())

        # 创建内存设备上下文
        hdc_mem = gdi32.CreateCompatibleDC(hdc_screen)
        if not hdc_mem:
            raise ctypes.WinError(ctypes.get_last_error())

        # 创建兼容位图
        hbm_mem = gdi32.CreateCompatibleBitmap(hdc_screen, w, h)
        if not hbm_mem:
            raise ctypes.WinError(ctypes.get_last_error())

        # 将位图选入内存DC
        hbm_old = gdi32.SelectObject(hdc_mem, hbm_mem)
        if not hbm_old:
            raise ctypes.WinError(ctypes.get_last_error())

        try:
            # 将桌面背景复制到内存DC
            if not gdi32.BitBlt(hdc_mem, 0, 0, w, h, hdc_screen, x, y, SRCCOPY):
                raise ctypes.WinError(ctypes.get_last_error())

            # 延迟一下再清除
            time.sleep(3)

            # 将原始背景复制回桌面，清除文字
            if not gdi32.BitBlt(hdc_screen, x, y, w, h, hdc_mem, 0, 0, SRCCOPY):
                raise ctypes.WinError(ctypes.get_last_error())

            print(f"已清除区域: x={x}, y={y}, w={w}, h={h}")

        finally:
            # 清理资源
            gdi32.SelectObject(hdc_mem, hbm_old)
            gdi32.DeleteObject(hbm_mem)
            gdi32.DeleteDC(hdc_mem)

        # 释放桌面DC
        user32.ReleaseDC(HWND_DESKTOP, hdc_screen)

    except Exception as e:
        print(f"清除错误: {str(e)}")


def draw_animated_text(text, size=100, x=100, y=100, color=RGB_RED, font_name="SimHei"):
    """绘制带有淡入淡出动画的文字"""
    try:
        # 获取桌面设备上下文
        hdc_screen = user32.GetDC(HWND_DESKTOP)
        if not hdc_screen:
            raise ctypes.WinError(ctypes.get_last_error())

        # 创建内存设备上下文
        hdc_mem = gdi32.CreateCompatibleDC(hdc_screen)
        if not hdc_mem:
            raise ctypes.WinError(ctypes.get_last_error())

        # 创建字体
        hfont = gdi32.CreateFontW(
            size, 0, 0, 0, 400,  # 高度、宽度、角度、方向、粗细
            0, 0, 0, 1, 4,  # 斜体、下划线、删除线、字符集、输出精度
            0, 0, 0, font_name  # 剪辑精度、质量、间距、字体
        )
        if not hfont:
            raise ctypes.WinError(ctypes.get_last_error())

        try:
            # 选入字体
            hfont_old = gdi32.SelectObject(hdc_mem, hfont)
            if not hfont_old:
                raise ctypes.WinError(ctypes.get_last_error())

            # 获取文本尺寸
            text_size = ctypes.wintypes.SIZE()
            if not gdi32.GetTextExtentPoint32W(hdc_mem, text, len(text), ctypes.byref(text_size)):
                raise ctypes.WinError(ctypes.get_last_error())

            # 创建兼容位图
            w, h = text_size.cx + 20, text_size.cy + 20  # 增加一些边距
            hbm_mem = gdi32.CreateCompatibleBitmap(hdc_screen, w, h)
            if not hbm_mem:
                raise ctypes.WinError(ctypes.get_last_error())

            # 将位图选入内存DC
            hbm_old = gdi32.SelectObject(hdc_mem, hbm_mem)
            if not hbm_old:
                raise ctypes.WinError(ctypes.get_last_error())

            try:
                # 保存原始背景
                hdc_bg = gdi32.CreateCompatibleDC(hdc_screen)
                hbm_bg = gdi32.CreateCompatibleBitmap(hdc_screen, w, h)
                gdi32.SelectObject(hdc_bg, hbm_bg)
                gdi32.BitBlt(hdc_bg, 0, 0, w, h, hdc_screen, x, y, SRCCOPY)

                # 设置透明背景
                prev_mode = gdi32.SetBkMode(hdc_mem, TRANSPARENT)
                gdi32.SetTextColor(hdc_mem, color)

                # 淡入效果
                for alpha in range(0, 256, 10):
                    # 清除内存DC
                    gdi32.BitBlt(hdc_mem, 0, 0, w, h, hdc_bg, 0, 0, SRCCOPY)

                    # 绘制文字
                    gdi32.TextOutW(hdc_mem, 10, 10, text, len(text))

                    # 复制到屏幕
                    gdi32.BitBlt(hdc_screen, x, y, w, h, hdc_mem, 0, 0, SRCCOPY)

                    time.sleep(0.02)

                # 保持显示3秒
                time.sleep(3)

                # 淡出效果
                for alpha in range(255, -1, -10):
                    # 清除内存DC
                    gdi32.BitBlt(hdc_mem, 0, 0, w, h, hdc_bg, 0, 0, SRCCOPY)

                    # 绘制文字
                    gdi32.TextOutW(hdc_mem, 10, 10, text, len(text))

                    # 复制到屏幕
                    gdi32.BitBlt(hdc_screen, x, y, w, h, hdc_mem, 0, 0, SRCCOPY)

                    time.sleep(0.02)

                # 恢复原始背景
                gdi32.BitBlt(hdc_screen, x, y, w, h, hdc_bg, 0, 0, SRCCOPY)

                print(f"已绘制动画文字: {text}")

            finally:
                # 恢复原背景模式
                gdi32.SetBkMode(hdc_mem, prev_mode)
                # 清理资源
                gdi32.SelectObject(hdc_mem, hbm_old)
                gdi32.DeleteObject(hbm_mem)
                gdi32.DeleteDC(hdc_bg)
                gdi32.DeleteObject(hbm_bg)

        finally:
            # 恢复原字体
            gdi32.SelectObject(hdc_mem, hfont_old)
            gdi32.DeleteObject(hfont)

        # 释放桌面DC
        user32.ReleaseDC(HWND_DESKTOP, hdc_screen)

    except Exception as e:
        print(f"动画绘制错误: {str(e)}")


def show_classification_text():
    """主函数：监控时间并在桌面上显示相应文本"""
    # 加载时间-文本配置并转换为秒数
    time_texts = load_time_texts()
    timed_events = {}
    for time_str, text in time_texts.items():
        try:
            minutes, seconds = time_str.split("分:")
            seconds = seconds.replace("秒", "").strip()
            total_seconds = int(minutes) * 60 + int(seconds)
            timed_events[total_seconds] = text
        except Exception as e:
            print(f"JSON格式错误，跳过无效条目 {time_str}：{e}")

    # 获取屏幕尺寸
    screen_width = user32.GetSystemMetrics(0)  # SM_CXSCREEN
    screen_height = user32.GetSystemMetrics(1)  # SM_CYSCREEN
    print(f"屏幕尺寸: {screen_width}x{screen_height}")

    start_time = int(time.time())
    displayed_events = set()
    event_positions = []  # 存储已显示事件的位置和尺寸

    # 颜色列表，循环使用
    colors = [RGB_RED, RGB_YELLOW, RGB_GREEN, RGB_BLUE]
    color_index = 0

    print("计时已开始...")
    print(f"设置的时间点: {timed_events}")

    try:
        while True:
            elapsed = int(time.time()) - start_time

            # 显示经过的时间
            minutes = elapsed // 60
            seconds = elapsed % 60
            print(f"\r已过去: {minutes}分{seconds}秒", end="", flush=True)

            # 检查是否需要显示新事件
            if elapsed in timed_events and elapsed not in displayed_events:
                text = timed_events[elapsed]
                color = colors[color_index % len(colors)]
                color_index += 1

                # 计算显示位置（在屏幕上部分布）
                event_count = len(event_positions)
                x = 900
                y = 200 + event_count * 120  # 每个事件间隔120像素

                # 确保不超出屏幕高度
                if y + 100 > screen_height:
                    y = screen_height - 150

                print(f"\n时间点 {minutes}分{seconds}秒: {text}")

                # 绘制带有动画效果的文字
                draw_animated_text(text, size=80, x=x, y=y, color=color)

                displayed_events.add(elapsed)

            time.sleep(0.1)

    except KeyboardInterrupt:
        print("\n程序正在退出...")

        # 清理所有显示的文字
        for pos in event_positions:
            if pos:
                clear_desktop_area(*pos)

        print("程序已退出")


def keyboard_listener():
    """键盘监听线程函数"""
    print("键盘监听已启动，等待 Ctrl+F11 开始计时...")

    while True:
        # 检查Ctrl+F11组合键
        # 获取Ctrl键状态
        ctrl_pressed = (user32.GetKeyState(0x11) & 0x8000) != 0  # VK_CONTROL
        # 获取F11键状态
        f11_pressed = (user32.GetKeyState(0x7A) & 0x8000) != 0  # VK_F11

        if ctrl_pressed and f11_pressed:
            print("\n检测到 Ctrl+F11，开始计时...")

            # 在桌面画出"逻辑开始"中文字
            draw_animated_text("逻辑开始", size=80, x=500, y=300, color=RGB_GREEN)

            # 启动计时线程
            timer_thread = threading.Thread(target=show_classification_text)
            timer_thread.daemon = True
            timer_thread.start()
            break

        time.sleep(0.1)


if __name__ == "__main__":
    try:
        # 启动键盘监听线程
        listener_thread = threading.Thread(target=keyboard_listener)
        listener_thread.daemon = True
        listener_thread.start()

        # 主线程等待
        while True:
            time.sleep(1)

    except KeyboardInterrupt:
        print("\n程序已退出")
